﻿using System;
using System.Linq;
using System.Windows.Media.Imaging;
using Notoric.Commanding.CommandBase;
using Notoric.Model.Elements;

namespace Notoric.ViewModel.Elements
{
    /// <summary>
    /// Adapts a <see cref="ImageSection"/>.
    /// </summary>
    public class ImageSection : Section
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="ImageSection"/> instance.
        /// </summary>
        /// <param name="adaptedElement">
        /// <para>
        /// Type: <see cref="ImageSectionElement"/>
        /// </para>
        /// <para>
        /// The model image section element adapted by this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="Page"/>
        /// </para>
        /// <para>
        /// The page that directly owns this section.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Any of the arguments is <see langword="null"/>.
        /// </exception>
        public ImageSection(ImageSectionElement adaptedElement, Page owner)
            : base(adaptedElement, owner)
        {
            if (adaptedElement.ImageFile != null)
                imageFile = FindOwner<Project>().Resources.First(r => r.AdaptedPart.Uri == adaptedElement.ImageFile);
        }

        #endregion

        #region ViewModelElement Mebers

        /// <inheritdoc/>
        public override string ElementNameKey
        {
            get { return elementNameKey; }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Creates an undoable command for setting the <see cref="ImageFile"/> property.
        /// </summary>
        /// <param name="resource">
        /// <para>
        /// Type: <see cref="Resource"/>
        /// </para>
        /// <para>
        /// The resource file that holds the image data.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="UndoableCommandBase"/>
        /// </para>
        /// <para>
        /// The created command ready for execution.
        /// </para>
        /// </returns>
        public UndoableCommandBase CreateSetImageFileCommand(Resource resource)
        {
            return new SetterCommand<Uri>(this, "ImageFile", (resource != null ? resource.AdaptedPart.Uri : null), UndoStack, RedoStack);
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the resource file that holds the data of the visualized image.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ImageFile"/>
        /// </para>
        /// <para>
        /// The resource file that holds the data of the visualized image.
        /// </para>
        /// </value>
        public Resource ImageFile
        {
            get { return imageFile; }
            set
            {
                if (UnsavedChanges.ContainsKey("ImageFile"))
                {
                    var cmd = (SetterCommand<Uri>)UnsavedChanges["ImageFile"];
                    cmd.Value = (value != null ? imageFile.AdaptedPart.Uri : null);
                }
                else
                    UnsavedChanges["ImageFile"] = CreateSetImageFileCommand(value);

                imageFile = value;
                RaisePropertyChanged("ImageFile");
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds a user-friendly name of this element.
        /// </summary>
        private const string elementNameKey = "ViewModel.ElementNames.ImageSection";
        /// <summary>
        /// Holds the resource that contains the image data.
        /// </summary>
        private Resource imageFile;

        #endregion
    }

    /// <summary>
    /// Implements the default interior of an image section.
    /// </summary>
    public class DefaultImageSectionInterior : SectionInterior
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="DefaultImageSectionInterior"/> instance.
        /// </summary>
        /// <param name="adaptedElement">
        /// <para>
        /// Type: <see cref="Model.Elements.DefaultImageSectionInterior"/>
        /// </para>
        /// <para>
        /// The adapted element
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="ImageSection"/>
        /// </para>
        /// <para>
        /// The image section that directly owns this element.
        /// </para>
        /// </param>
        public DefaultImageSectionInterior(Model.Elements.DefaultImageSectionInterior adaptedElement, ImageSection owner)
            : base(adaptedElement, owner, owner.UndoStack, owner.RedoStack)
        {
        }

        #endregion

        #region ViewModelElement Members

        /// <inheritdoc/>
        public override string ElementNameKey
        {
            get { return FindOwner<ImageSection>().ElementNameKey; }
        }

        #endregion

        #region SectionInterior Members

        /// <inheritdoc/>
        protected override void ClearSelectionCore()
        {
            
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Loads the image data from the project package.
        /// </summary>
        /// <returns>A new <see cref="BitmapSource"/> instance holding the image data</returns>
        private BitmapSource LoadImage()
        {
            if (FindOwner<ImageSection>().ImageFile == null)
                return null;

            BitmapDecoder decoder = null;
            var imageFile = FindOwner<ImageSection>().ImageFile;

            switch (imageFile.Extension.ToLower())
            {
                case ".bmp":
                    decoder = new BmpBitmapDecoder(imageFile.InputStream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                    break;
                case ".jpg":
                case ".jpeg":
                    decoder = new JpegBitmapDecoder(imageFile.InputStream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                    break;
                case ".gif":
                    decoder = new GifBitmapDecoder(imageFile.InputStream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                    break;
                case ".png":
                    decoder = new PngBitmapDecoder(imageFile.InputStream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                    break;
                case ".tif":
                    decoder = new TiffBitmapDecoder(imageFile.InputStream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                    break;
                case ".wdp":
                    decoder = new TiffBitmapDecoder(imageFile.InputStream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                    break;
                case ".ico":
                    decoder = new IconBitmapDecoder(imageFile.InputStream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                    break;
            }

            return decoder.Frames[0];
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the image source.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="BitmapSource"/>
        /// </para>
        /// <para>
        /// The image source.
        /// </para>
        /// </value>
        public BitmapSource ImageSource
        {
            get
            {
                if (imageSource == null)
                    imageSource = LoadImage();

                return imageSource;
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the image source.
        /// </summary>
        private BitmapSource imageSource;

        #endregion
    }
}
